//////////////////////////////////////////////////////////////////////////
//
// File Name		: MTCPConnection.cpp
//
// Description		: Defines the exported functions for the DLL application.
//
// Author			: James.Gu
//
// Date				: 09/25/2016
//
//////////////////////////////////////////////////////////////////////////
#include "MTCPConnection.h"

#include <mutex>
#include <cassert>

#include <cstdlib>
#include <iostream>
#include <string>

#include <boost/bind.hpp>
#include <boost/asio.hpp>

#define MP_SUCCESSFUL		0
#define MP_SOCKET_FAILED	-2					// socket failed

#define ASSERT			assert


std::string						peer_address = std::string("127.0.0.1");
int								peer_port = 61804;

boost::asio::io_service			ioservice;
boost::asio::ip::tcp::socket	gs(ioservice);

std::mutex						gMtx;
int								gRcvTimeouts = 5000;

// auto reconnect
static void reconnect()
{
	if (gs.is_open())
	{
		return;
	}

	boost::asio::ip::tcp::endpoint
		peer_endpoint(boost::asio::ip::address::from_string(peer_address.c_str()), peer_port);
	boost::system::error_code ec;

	gs.connect(peer_endpoint, ec);
}

const char * getVersion()
{
	return "MTCP Wapper v2.2";
}

// open session
int mp_open_session(const char * address, int port, int timeout)
{
	printf("Try to connect to %s:%d with time out : %d\n", address, port, timeout);
	assert(address);
	assert(port > 0);

	std::unique_lock<std::mutex>		_lck(gMtx);

	if (gs.is_open())
	{
		return MP_SOCKET_FAILED;
	}

	peer_address = std::string(address);
	peer_port = port;

	boost::asio::ip::tcp::endpoint 
		peer_endpoint(boost::asio::ip::address::from_string(peer_address.c_str()), peer_port);
	boost::system::error_code ec;

	gs.connect(peer_endpoint, ec);
	if (ec)
	{
		gs.close();
		return MP_SOCKET_FAILED;
	}

	gRcvTimeouts = timeout;

	return MP_SUCCESSFUL;
}

// close session
void mp_close_session()
{
	boost::system::error_code ec;
	gs.close(ec);
}

// send a message
int mp_send_data(const char * buffer, int length)
{
	ASSERT(buffer);
	ASSERT(length > 0);

	if (!gs.is_open())
	{
		reconnect();

		if (!gs.is_open())
		{
			return MP_SOCKET_FAILED;
		}
	}

	ASSERT(gs.is_open());

	boost::system::error_code ec;

	size_t snd_cnt = 0;
	while (snd_cnt<length)
	{
		size_t snd = gs.write_some(boost::asio::buffer((buffer+snd_cnt), (length-snd_cnt)), ec);
		if ((ec == boost::asio::error::eof) || (snd<0))
		{
			gs.close(ec);
			return MP_SOCKET_FAILED;
		}

		snd_cnt += snd;
	};

	return snd_cnt;
}

// read some data from peer host
int mp_recv_data(char * buffer, int size)
{
	ASSERT(buffer);
	ASSERT(size > 0);

	if (!gs.is_open())
	{
		reconnect();
		if (!gs.is_open())
		{
			return MP_SOCKET_FAILED;
		}
	}

	boost::system::error_code ec;

	size_t rcv_cnt = 0;
	size_t rcv = 0;
	/*while (rcv_cnt<size)
	{
		rcv = gs.read_some(boost::asio::buffer((buffer+rcv_cnt), (size-rcv_cnt)), ec);
		std::cout << "byte of rcv_msg:" << rcv << std::endl;
		std::cout << "rcv_msg:" << buffer << std::endl;
		if ((ec==boost::asio::error::eof) || (rcv<0))
		{
			gs.close(ec);
			return MP_SOCKET_FAILED;
		}
		if (rcv == 0){
			break;
		}
		rcv_cnt += rcv;
	};*/
	rcv = gs.read_some(boost::asio::buffer((buffer + rcv_cnt), (size - rcv_cnt)), ec);
	std::cout << "byte of rcv_msg:" << rcv << std::endl;
	std::cout << "rcv_msg:" << buffer << std::endl;

	return rcv_cnt;
}

int Open(const char * address, int port, int timeout)
{
	return mp_open_session(address, port,5000);
}

void Close()
{
	mp_close_session();
}

/////////////////////////////////
int ReadDataFromFile_float(const char * file, float * data,int * count)
{
	FILE * f = fopen(file, "r");
	if (f==NULL)
	{
		count = 0;
		return -1;
	}
	fseek(f, 0, SEEK_END);
	long size = ftell(f);
	char * buffer = new char[size + 1];
	memset(buffer, 0, size + 1);
	fread(buffer, size, 1, f);
	fclose(f);

	char * exp = ",";
	char * token = strtok(buffer, exp);
	int index = 0;

	while (token)
	{
		data[index++] = strtof(token, nullptr);
		token = strtok(NULL, exp);
	}
	*count = index;
	delete[] buffer;
	return 0;
}

int ReadDataFromFile_int(const char * file, int * data, int * count)
{
	FILE * f = fopen(file, "r");
	fseek(f, 0, SEEK_END);
	long size = ftell(f);
	char * buffer = new char[size + 1];
	memset(buffer, 0, size + 1);
	fread(buffer, size, 1, f);
	fclose(f);

	char * exp = ",";
	char * token = strtok(buffer, exp);
	int index = 0;

	while (token)
	{
		data[index++] = strtol(token, nullptr, 10);
		token = strtok(NULL, exp);
	}
	*count = index;
	delete[] buffer;
	return 0;
}
//////////////////////////////////////////////////////////////////////////
// end file(s)
//////////////////////////////////////////////////////////////////////////
